
/**
 *	\file Definition of the nmn::singleton class.
 *	\author Sean Tromans
 */

#ifndef	NMN_SINGLETON_HPP
#define	NMN_SINGLETON_HPP

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <needs_more_ninja/interface.hpp>
#include <needs_more_ninja/preprocessor/assert/assert.hpp>

namespace nmn
{

	/**
	 *	Singleton base class object.
	 *	\author Sean Tromans
	 */
	template < typename TInterface >
	class	singleton	:		private boost::noncopyable
							,	public interface_
	{
		//
		//	Public Member Types
		//
		public:

			/** The type of this interface. */
			typedef		TInterface									singleton_interface_type;

			/** A reference counted smart pointer to this singleton. */
			typedef		boost::shared_ptr<singleton_interface_type>	singleton_ptr_type;

		//
		//	Public Static Member Functions
		//
		public:

			/**
			 *	Creates a singleton of the interface type with the default allocator.
			 *	@return The newly created singleton.
			 *	\author Sean Tromans
			 */
			static singleton_ptr_type	create_singleton( )
			{
				return create_singleton< singleton_interface_type, std::allocator< singleton_interface_type > >( std::allocator< singleton_interface_type >( ) );
			}

			/**
			 *	Creates a singleton of the interface type with the specified allocator.
			 *	@param a A specific instance of the allocator to use. Defaults to a default constructed allocator.
			 *	@return The newly created singleton.
			 *	\author Sean Tromans
			 */
			template< typename A >
			static	singleton_ptr_type	create_singleton( A const & a )
			{
				return create_singleton< singleton_interface_type, A >( a );
			}

			/**
			 *	Creates a singleton of the derived classes type with the default allocator.
			 *	@return The newly created singleton.
			 *	\author Sean Tromans
			 */
			template< typename TChild >
			static	singleton_ptr_type	create_singleton( )
			{
				return create_singleton< TChild, std::allocator< TChild > >( );
			}

			/**
			 *	Creates a singleton of the derived classes type with the specified allocator.
			 *	@param a A specific instance of the allocator to use. Defaults to a default constructed allocator.
			 *	@return The newly created singleton.
			 *	\author Sean Tromans
			 */
			template< typename TChild, typename A >
			static	singleton_ptr_type	create_singleton( A const & a = A( ) )
			{
				//NMN_ASSERT_MESSAGE( !is_singleton_valid( ), "Singleton has already been created." );
				s_interface = boost::allocate_shared< TChild >( a );
				return s_interface;
			}

			/**
			 *	Sets the singleton to be a pre-allocated smart pointer to the interface type.
			 *	@param ptr The smart pointer to become the singleton.
			 *	@return The newly created singleton.
			 *	\author Sean Tromans.
			 */
			static singleton_ptr_type assign_singleton( singleton_ptr_type ptr )
			{
				//NMN_ASSERT_MESSAGE( !is_singleton_valid( ), "Singleton has already been created." );
				s_interface = ptr;
				return s_interface;
			}

			/**
			 *	Returns whether the singleton has been created or not.
			 *	\author Sean Tromans
			 */
			static bool is_singleton_valid( )
			{
				return s_interface != 0;
			}

			/**
			 *	Returns a reference to the smart pointer of the singleton.
			 *	\author Sean Tromans
			 */
			static singleton_ptr_type get_singleton( )
			{
				//NMN_ASSERT_MESSAGE( is_singleton_valid( ), "Singleton has not been created." );
				return s_interface;
			}

			/**
			 *	Destroys the singletons copy of the smart pointer.
			 *	\author Sean Tromans
			 */
			static void destroy_singleton( )
			{
				s_interface.reset( );
			}

		//
		//	Protected Member Functions
		//
		protected:

			/**
			 *	Protected constructor to prevent instantiation.
			 *	\author Sean Tromans
			 */
			singleton( ) {}

		//
		//	Private Static Member Variables
		//
		private:

			static singleton_ptr_type	s_interface;	///<	The smart pointer to the singleton.
	};

	template< typename TInterface >
	typename singleton<TInterface>::singleton_ptr_type	singleton<TInterface>::s_interface;

};

#endif	//NMN_SINGLETON_HPP
